<?php
/**
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2018/10/10
 * Time: 17:43
 */

namespace App\Traits;

use Illuminate\Support\Facades\Log;

trait ModelTraits
{
    /**
     * 必须定义
     * @var string
     */
    protected $modelClass;

    /**
     * modelClass 实例化后的类
     * @var BaseModel
     */
    protected $model;

    /**
     * modelClass 原始类
     * @var BaseModel
     */
    protected $origin_model;

    /**
     * @param bool $new
     * @return BaseModel|mixed
     */
    public function model($new = false)
    {
        if ($this->model and $new == false) {
            return $this->model;
        }

        $this->origin_model = $this->model = app()->make($this->modelClass);

        return $this->model;
    }

    /**
     * @param $val
     * @param string $field
     * @param array $columns
     * @param bool $throw
     * @return mixed
     * @throws \Exception
     */
    public function find($val, $field='uuid', $columns=['*'], $throw=true)
    {
        if (is_array($val)) {
            $res = $this->model->whereIn($field, $val);
        } else {
            $res = $this->model->where($field, $val);
        }
        $res = $res->get($columns);

        if (empty($res)) {
            if ($throw) {
                throw new \Exception('未找到或无法访问!');
            }
            $res = [];
        }
        return $res;
    }

    /**
     * 根据主键查找数据
     * @param $id
     * @param array $columns
     * @param bool $throw
     * @return mixed
     * @throws \Exception
     */
    public function findById($id, $columns=['*'], $throw=false)
    {
        $res = $this->find($id, $this->model::COL_ID, $columns, $throw);

        if (is_array($id)) {
            return $res;
        }

        return $res->first();
    }

    /**
     * @param $id
     * @param array $columns
     * @return mixed
     * @throws \Exception
     */
    public function findByIdOrFail($id, $columns=['*'])
    {
        return $this->findById($id, $columns, true);
    }

    /**
     * 根据uuid查找数据
     * @param $uuid
     * @param array $columns
     * @param bool $throw
     * @return mixed
     * @throws \Exception
     */
    public function findByUuid($uuid, $columns=['*'], $throw=false)
    {
        $res = $this->find($uuid, $this->model::COL_UUID, $columns, $throw);

        if (is_array($uuid)) {
            return $res;
        }

        return $res->first();
    }

    /**
     * @param $uuid
     * @param array $columns
     * @return mixed
     * @throws \Exception
     */
    public function findByUuidOrFail($uuid, $columns=['*'])
    {
        return $this->findByUuid($uuid, $columns, true);
    }

    /**
     * 获取插入的主键id
     * @param $columns
     * @return mixed
     */
    public function insertGetId($columns)
    {
        return $this->model->insertGetId($columns);
    }

    /**
     * 新增数据
     * @param $postData
     * @param bool $throw
     * @return BaseModel
     * @throws \Exception
     */
    public function saveData($postData, $throw=true)
    {
        $postData = filter_null($postData);
        if ($this->model->fill($postData)->save()) {
            return $this->model;
        }

        if ($throw) {
            throw new \Exception('新增失败');
        }
    }

    /**
     * 根据主键更新
     * @param $id 如果是数组请使用事物
     * @param $data
     * @return mixed
     * @throws \Exception
     */
    public function updateById($id, $data)
    {
        $res = $this->findById($id, ['*'], true);

        if (is_array($id)) {
            foreach ($res as $r) {
                foreach ($data as $k=>$v) {
                    $r->$k = $v ?? '';
                }
                $r->save();
            }
            return true;
        } else {
            foreach ($data as $k=>$v) {
                $res->$k = $v ?? '';
            }
            return $res->save();
        }
    }

    /**
     * 根据uuid更新
     * @param $uuid 如果是数组请使用事物
     * @param $data
     * @return mixed
     * @throws \Exception
     */
    public function updateByUuid($uuid, $data)
    {
        $res = $this->findByUuid($uuid, ['*'], true);

        if (is_array($uuid)) {
            foreach ($res as $r) {
                foreach ($data as $k=>$v) {
                    $r->$k = $v ?? '';
                }
                $r->save();
            }
            return true;
        } else {
            foreach ($data as $k=>$v) {
                $res->$k = $v ?? '';
            }
            return $res->save();
        }
    }

    /**
     * 根据主键删除
     * @param $id
     * @throws \Exception
     */
    public function removeById($id)
    {
        $this->updateById($id, [$this->model::COL_IS_ENABLE => 0]);
    }

    /**
     * 根据uuid删除
     * @param $uuid
     * @return mixed
     * @throws \Exception
     */
    public function removeByUuid($uuid)
    {
        return $this->updateByUuid($uuid, [$this->model::COL_IS_ENABLE => 0]);
    }

    /**
     * @param $val
     * @param $field
     * @return mixed
     * @throws \Exception
     */
    public function removeByField($val, $field)
    {
        $obj = $this->find($val, $field)->first();
        return $obj->update([$this->model::COL_IS_ENABLE => 0]);
    }

    /**
     * 获取所有
     * @param array $columns
     * @return mixed
     */
    public function getAll($columns=['*'])
    {
        return $this->model::all($columns);
    }

    /**
     * 条件搜索
     * @param $model
     * @param array $search
     * @param array $option
     * @return mixed
     */
    public final function searcher($model, $search=[], $option=['orderBy'=>['created_at'=>'desc']])
    {
        \DB::enableQueryLog();
        try {
            foreach ($search as $s) {
                $field = $s['index'];
                $value = $s['value'];

                $col_arr = explode(',', $field); # 多字段like查询

                switch ($s['operate']) {
                    case '=' :
                        $model = $model->where($field, $value);
                        break;

                    case '!=' :
                        $model = $model->where($field, '<>', $value);
                        break;

                    case 'in' :
                        $model = $model->whereIn($field, $value);
                        break;

                    case 'not_in' :
                        $model = $model->whereNotIn($field, $value);
                        break;

                    case 'is_null' :
                        $model = $model->whereNull($field);
                        break;

                    case 'not_null' :
                        $model = $model->whereNotNull($field);
                        break;

                    case '%like%' :
                        $model = $model->where(function($query)use($col_arr, $value) {
                            foreach ($col_arr as $col) {
                                $query->orWhere($col, 'LIKE', "%{$value}%");
                            }
                        });
                        break;

                    case 'not_like' :
                        $model = $model->where(function($query)use($col_arr, $value) {
                            foreach ($col_arr as $col) {
                                $query->orWhere($col, 'NOT LIKE', "%{$value}%");
                            }
                        });
                        break;

                    case '%like' :
                        $model = $model->where(function($query)use($col_arr, $value) {
                            foreach ($col_arr as $col) {
                                $query->orWhere($col, 'LIKE', "%{$value}");
                            }
                        });
                        break;

                    case 'like%' :
                        $model = $model->where(function($query)use($col_arr, $value) {
                            foreach ($col_arr as $col) {
                                $query->orWhere($col, 'LIKE', "{$value}%");
                            }
                        });
                        break;

                    case 'between' :
                        $model = $model->whereBetween($field, $value);
                        break;

                    case 'orderBy' :
                        $model = $model->orderBy($field, $value);
                        break;

                    default:
                        $model = $model->where($field, $s['operate'], $value);
                        break;
                }
            }
            
            foreach ($option['orderBy'] as $key=>$val) {
                $model = $model->orderBy($key, $val);
            }

            return $model;
        } catch (\Exception $e) {
            \Log::error('条件搜索错误', [$e]);
        }
    }
}
